#include "Fraction.h"
template<typename R, typename traits>
fraction<R,traits>::fraction(R num, R den):numerator(num){
    R r(0);
    if(den==r) throw typename fraction<R,traits>::fraction_exception();
    denominator = den;  //Sets conveniently the denominator
    simplify();  //Calls simplify function
}

template<typename R, typename traits>
fraction<R,traits>::fraction(std::istream& is){
    read(is);  //read the fraction from the stream, leaving the cursor at the end
}

//Overload the operators
template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::operator+(fraction<R,traits>& right){
    fraction f(denominator*right.numerator+numerator*right.denominator,right.denominator*denominator);
    return f;
}  //operator+

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::operator-(fraction<R,traits>& right){
    fraction f(numerator*right.denominator-denominator*right.numerator,right.denominator*denominator);
    return f;
}  //operator-

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::operator*(fraction<R,traits>& right){
    fraction f(numerator*right.numerator,right.denominator*denominator);
    return f;
}  //operator*

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::operator*(R& right){
    fraction f(numerator*right,right.denominator);
    return f;
}

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::operator/(fraction<R,traits>& right){
    fraction f(numerator*right.denominator,denominator*right.numerator);
    return f;
}  //operator/

template<typename R, typename traits>
fraction<R,traits>& fraction<R,traits>::operator=(fraction<R,traits>& right){
    numerator = right.numerator;
    denominator = right.denominator;
    return right;
}

template<typename R, typename traits>
bool fraction<R,traits>::operator==(fraction<R,traits>& right){
     return denominator*right.numerator == numerator*right.denominator;
}

template<typename R, typename traits>
bool fraction<R,traits>::operator!=(fraction<R,traits>& right){
     return denominator*right.numerator != numerator*right.denominator;
}
//Read and write operators overload (should be defined in another file)
template<typename R, typename traits>
std::istream& operator>>(std::istream& is, fraction<R,traits>& f){
    return f.read(is);
}

template<typename R, typename traits>
std::ostream& operator<<(std::ostream& os, fraction<R,traits> f){
    return f.write(os);
}

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::power(int pow){
    fraction result(1);
    int n = pow >= 0 ? pow : -pow;
    int r = 1;
    while(n != 0){
            if(r == 1) result = *this * result;
            n = n / 2;
            if(n != 0) result = result * result;
            r = n % 2;
    }
    if(pow < 0) return result.inverse();
    return result;
}

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::inverse(){
            if(numerator==0) throw(fraction<R,traits>::fraction_exception);
            fraction result(denominator,numerator);
            return result;
}

template<typename R, typename traits>
fraction<R,traits> fraction<R,traits>::symmetric(){
    fraction result(-numerator,denominator);
    return result;
}

template<typename R, typename traits>
std::istream& fraction<R,traits>::read(std::istream& is){
    traits::read(is, numerator, denominator);
    if(denominator == 0) throw typename fraction<R,traits>::fraction_exception();
    std::cout<<"numerator: "<<(*this).numerator<<" denominator: "<<(*this).denominator<<std::endl;
    return is;
}

template<typename R, typename traits>
std::ostream& fraction<R,traits>::write(std::ostream& os){
    R ru(1);
    R rz(0);
    if(denominator == ru || numerator == rz) os<<numerator;
    else os<<numerator<<"/"<<denominator;
    return os;
}

//This function should implement some traits in order to allow users to define
//how a fraction may simplify over some ring
template<typename R, typename traits>
void fraction<R,traits>::simplify(){
     traits::simplify(numerator, denominator);
}

//--------------------------------------------------------
//Those functions are independent from fraction and should be addressed elsewhere
//--------------------------------------------------------
template<typename T>
T gcd(T& t1, T& t2){
         T tmp1 = t1<t2 ? t2 : t1;
         T tmp2 = t1<t2 ? t1 : t2;
         T nt(0);
         while(tmp2 != nt){
                    T r = tmp1 % tmp2;
                    tmp1 = tmp2;
                    tmp2 = r;
         }
         return tmp1;
}
